#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/file.h>

//define macro
#define INS 5

//define global variable
char num_file[] = "./num.txt";
char lock_file[] = "./lock.txt";

//define struct
struct Num{
    int now;
    int sum;
};

struct Num num;

size_t get_num(struct Num* num){
    FILE* file = fopen(num_file, "r");
    if(file == NULL){
        fclose(file);
        perror("fopen");
        return -1;
    }
    size_t nr = fread(num, sizeof(struct Num), 1, file);
    if(nr < 0){
        fclose(file);
        perror("fread");
        return -1;
    }
    fclose(file);
    return nr;
}

size_t set_num(struct Num* num){
    FILE* file = fopen(num_file, "w");
    size_t nw = fwrite(num, sizeof(struct Num), 1, file);
    fclose(file);
    return nw;
}

void do_add(int index, int end){
    while(1){
        FILE* lock = fopen(lock_file, "w");
        flock(lock->_fileno, LOCK_EX);
        if(get_num(&num) < 0){
            fclose(lock);
            continue;
        }
        if(num.now > end){
            fclose(lock);
            break;
        }
        printf("I am %d subprocess, now = %d, sum = %d\n", index, num.now, num.sum);
        num.sum += num.now;
        num.now++;
        set_num(&num);
        flock(lock->_fileno, LOCK_UN);
        fclose(lock);
    }
    return;
}

int main(int argc, char** argv){
    //parse the argv
    int start, end;
    int opt;
    int s_flag = 0, e_flag = 0;
    while((opt = getopt(argc, argv, "s:e:")) != -1){
        switch(opt){
            case 's':
                s_flag = 1;
                start = atoi(optarg);
                break;
            case 'e':
                e_flag = 1;
                end = atoi(optarg);
                break;
            default:
                fprintf(stderr, "Usage : %s -s num1 -e num2\n", argv[0]);
                exit(1);
        }
    }

    //check the args and initial the file
    if((s_flag && e_flag) != 1){
        fprintf(stderr, "Usage : %s -s num1 -e num2\n", argv[0]);
        exit(-1);
    }
    printf("start = %d, end = %d\n", start, end);
    num.now = start;
    num.sum = 0;
    set_num(&num);
    FILE* n_file = fopen(num_file, "w");
    size_t nw = fwrite(&num, sizeof(struct Num), 1, n_file);
    if(nw != 1){
        perror("fwrite");
        fclose(n_file);
        exit(-1);
    }
    fclose(n_file);

    //fork the subprocess
    int i = 0;
    pid_t pid;
    while(i < INS){
        if((pid = fork()) < 0){
            perror("fork");
            exit(-1);
        }
        else if(pid == 0){
            do_add(i, end);
            exit(0);
        }
        i++;
    }

    int ins = INS;
    while(ins){
        wait(NULL);
        ins--;
    }
    get_num(&num);
    printf("sum = %d\n", num.sum);
    return 0;
}